import pandas as pd
import numpy as np

s = np.arange(2, 34)
df = pd.read_csv(
    '/Users/user/PycharmProjects/text1/files/Export-ID-115213036186490-2023-10-07T07_00_00-2023-10-07T23_59_59-D84-BATTERY-AND-VHB-INSTALL-Versions-3.csv',
    header=1)

# 查询  df.query(expr)使用布尔表达式查询DataFrame列，
# 表达式是一个字符串，类似SQL的where从句。
# df.query('表达式')
# df.query('Q1 > @a+40')
#
# # 筛选 df.filter()可以对行名和列名进行筛选，支持模糊匹配、正则表达式。
# df.filter(items=['Q1', 'Q2'])  # 选择两列
# df.filter(regex='Q', axis=1)  # 列名包含Q的列
# df.filter(regex='e$', axis=1)  # 以e结尾的列
# df.filter(like='2', axis=0)  # 索引中有2的
# df.filter(regex='^2', axis=0).filter(like='Q', axis=1)

# 返回每列的数据类型
print(df.convert_dtypes().dtypes)
print(df.infer_objects().dtypes)

# 类型转换
df.astype('int32')  # 所有数据类型转换
df.astype({'col1': 'int32'})  # 指定字段转为指定类型
df['name'].astype('object')

# 当数据格式不具备转换为目标类型的条件时，需要先处理数据
# eg： "89.3%" -> 浮点数
df.rate.apply(lambda x: x.replace('%', '')).astype('float') / 1000

# 转换为时间格式
df['Special Build Description'] = df['Special Build Description'].astype('datetime64[ns]')

# 索引排序
# 按索引排序，默认升序，降序：ascending=False
df.sort_index(ascending=True)

# 按列索引名排序（在列索引方向上排序）会把这列按照列名顺序排列
df.sort_index(axis=1, ascending=False)

df.reindex()  # 指定自己定义顺序的索引，实现行和列的顺序重新定义

# 数值排序
# sort_values() 数字按大小顺序，字符按字母顺序
# Series和DataFrame都支持
# DataFrame需要传入一个或多个排序的列名
# 默认排序是升序，但是可以指定排序方式
df.sort_values(by=['team', 'name'], ascending=[True, False])

# df按指定字段排序
df.sort_values(by=['team'])

# 索引重新0-（n-1）排
df.sort_values('team', ignore_index=True)

# replace(old, new) 实现数据的批量替换
# 值可以是数字，也可以是列表、字典..

# 参数method='pad'/'ffill'/'bfill'/None

# 使用正则表达式
df.replace(to_replace=r'^ba.$', value='new', regex=True)

df.fillna(0)  # 将空值全部修改为0
# {'backfill', 'bfill', 'pad', 'ffill', None} 默认为None
df.fillna(method='ffill')  # 将空值都修改为其前一个值
df.fillna(value='0', limit=1)  # 只替换第一个

df.rename(columns={'team': 'class'})  # 修改表头
df.rename(index={0: "x"})  # 修改索引

df.rename(index=str)  # 修改类型
df.rename(str.lower, axis='columns')  # 传索引类型

# 对索引名进行修改
s.rename_axis("animal")
df.rename_axis("animal")  # 默认是列索引
df.rename_axis("limbs", axis="columns")  # 指定行索引
# 索引为多层索引时可以将type修改为class
df.rename_axis(index={'type': 'class'})

# 可以用set_axis进行设置修改
s.set_axis(['a', 'b', 'c'], axis=0)
df.set_axis(['i', 'ii'], axis='columns', inplace=True)

# 插入列，  df.insert(loc, column, value)
# loc是一个数字，代表新列所在的位置，使用数字索引
# column为新的列名
# value为列的值，一般是Series

df.insert(2, 'total', df.sum(1))

# 如果已经存在相同的数据列会报错
# 可以传入allow_duplicates=True插入同名列
# 如果希望新列位于最后，可以在loc传入len(df.columns)
df.insert(2, 'total', df.sum(1))

# 追加合并
# pd.append()	 追加一个新行

pd.concat([s1, s2])  # 连接两个s或者df
pd.concat([s1, s2], ignore_index=True)  # 索引重新编
pd.concat([s1, s2], keys=['s1', 's2'], names=['Series name', 'row ID'])
# 原数索引不变，增加一个一层索引（keys的内容），变成多层索引

# df同理
pd.concat([df1, df2])
pd.concat([df1, df3], sort=False)
pd.concat([df1, df3], join="inner")  # 连接相同列
pd.concat([df1, df4], axis=1)  # 连接列

# 删除

# 方法一： pop()
s.pop()  # 删除指定索引的数据同时返回这个被删除的值
df.pop('ss')  # 删除指定列并返回这个被删除的列

# 方法二：反选法
# 将需要的数据筛选出来赋值给原变量，实现删除

# 删除空值
df.dropna()  # 一行中有一个缺失值就删除
df.dropna(axis='columns')  # 只保留全有值的列
df.dropna(how='all')  # 行和列全没值才删除
df.dropna(thresh=2)  # 至少有两个空值才删除
df.dropna(inplace=True)  # 删除并替换生效

#
# apply()可以对DataFrame按行和列进行函数处理，也支持Series
# 如果是Series，逐个传入具体值
# 如果是DataFrame，逐行或逐列传入
# eg
# 将name全部变为小写
df.name.apply(lambda x: x.lower())


# 去掉一个最高分和一个最低分再算出平均分
def my_mean(s):
    max_min_ser = pd.Series([-s.max(), -s.min()])
    return s.append(max_min_ser).sum() / (s.count() - 2)


# 对数字列应用函数
df.select_dtypes(include='number').apply(my_mean)
# apply()可以应用的函数类型如下
#df.apply(fun) # 自定义
df.apply(max) # Python内置函数
df.apply(lambda x: x*2) # lambda
df.apply(np.mean) # Numpy等其他库函数
df.apply(pd.Series.first_valid_index) # Pandas自带的函数
